package com.zhu.pre.service.impl;

import com.sanploy.common.conf.PubliceVariable;
import com.sanploy.common.domain.*;
import com.sanploy.common.domain.dto.OrderDto;
import com.sanploy.common.domain.dto.ReduceStockDto;
import com.sanploy.common.domain.vo.GoodsDetailVo;
import com.sanploy.common.domain.vo.OrderListVo;
import com.sanploy.common.enums.*;
import com.sanploy.common.util.CommonUtil;
import com.sanploy.common.vo.BaseException;

import com.sanploy.wechat.dto.PayNotify;
import com.sanploy.wechat.dto.PaySign;
import com.sanploy.wechat.service.WechatSmallService;
import com.zhu.pre.mapper.MOrderMapper;
import com.zhu.pre.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * Created by zhu yingzhi on 2017/9/29.
 * @author yingzhi zhu
 * 手机订单逻辑处理接口实现
 * TODO payNotify 验证参数请求。
 */
@Service
public class MOrderServiceImpl implements MOrderService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MGoodsService goodsService;

    @Autowired
    private GoodsAttrService goodsAttrService;

    @Autowired
    private MUserService mUserService;

    @Autowired
    private WechatSmallService wechatSmallService;

    @Autowired
    private MOrderMapper mOrderMapper;

    @Autowired
    private CartService cartService;

    //保存订单 Spring的默认回滚RuntimeException
    @Transactional(rollbackFor = {Exception.class} )
    @Override
    public PaySign saveOrder(OrderDto orderDto) throws BaseException, IOException, NoSuchAlgorithmException {

        return OrderSaveUtil(orderDto);
    }

    //查找订单通过状态
    @Override
    public List<OrderListVo> findOrderByStatus(String token,String status) throws BaseException {
        User user = Optional.ofNullable((User)redisTemplate.opsForValue().get(token)).
                orElseThrow(()->new BaseException(Meta.AuthFail));
        // TODO 把这部分注销了
        //        //用户未取消订单自动取消
//        orderTimerService.userOrderAutoCancel(user.getId());
//        //用户未确认订单自动确认
//        orderTimerService.userOrderAutoConfirm(user.getId());

        return mOrderMapper.findOrderItem(user.getId(),status);
    }


    //微信异步支付 结果返回处理
    @Override
    public String payNotify(ServletRequest servletRequest) throws IOException {
        System.out.println(servletRequest.getContentType()+" POST");
        BufferedReader bufferedReader= new BufferedReader(new InputStreamReader(servletRequest.getInputStream())); //获得XML数据
        String line = null;
        StringBuffer stringBuffer = new StringBuffer();
        while ((line = bufferedReader.readLine())!=null){
            stringBuffer.append(line);
        }
        System.out.println(stringBuffer.toString());
        PayNotify payNotify = wechatSmallService.notifyPay(stringBuffer.toString());
        if (payNotify.getReturn_code().equals("SUCCESS")){ //如果支付成功
            String openid = payNotify.getOpenid();
            String order_id = payNotify.getOut_trade_no();
            mOrderMapper.updateOrderStatus(order_id,OrderStatus.WaitGoods.toString(),mUserService.findUserByOpenId(openid).getId()); //更新订单状态
            mOrderMapper.updatePayStatus(order_id,OrderPayStatus.Paid.toString(),mUserService.findUserByOpenId(openid).getId());
            //从自动取消队列中移除
//            orderTimerService.userOrderCancelDelete(order_id);
            //删除 redis中的库存信息
            redisTemplate.delete(PubliceVariable.RedisOrderStock+order_id);
//            messageService.sendMessage(new Message("用户已支付，订单号"+order_id+"。下单时间："+CommonUtil.getTimeNormal()+"。请及时处理",CommonUtil.getTimeNormal(),
//                    MessageType.OrderPay,"admin"),"/messageSocket/chain/newMessage");
            return "<xml>\n" +
                    "  <return_code><![CDATA[SUCCESS]]></return_code>\n" +
                    "  <return_msg><![CDATA[OK]]></return_msg>\n" +
                    "</xml>";
        }
        return "<xml>\n" +
                "  <return_code><![CDATA[FAIL]]></return_code>\n" +
                "  <return_msg><![CDATA[失败]]></return_msg>\n" +
                "</xml>";
    }

    //通过OrderId 查找
    @Override
    public OrderListVo findOrderById(String token, String orderId) throws BaseException {
        return mOrderMapper.findOrderById(orderId,Optional.ofNullable((User)redisTemplate.opsForValue().get(token)).
                orElseThrow(()->new BaseException(Meta.AuthFail)).getId());
    }

    //支付订单
    @Override
    public PaySign payOrder(String token, String orderId) throws Exception {
        User  user = Optional.ofNullable((User)redisTemplate.opsForValue().get(token)).
                orElseThrow(()->new BaseException(Meta.AuthFail));
        return wechatSmallService.unifiedOrder(user.getOpenid(),findOrderById(token,orderId).getOrder_price(),orderId);
    }

    //取消订单
    @Override
    public int cancelOrder(String token, String orderId) throws BaseException {
        if (CommonUtil.judgeRUD(mOrderMapper.cancerOrder(orderId,OrderStatus.Cancelled.toString(),CommonUtil.getTimeNormal(),Optional.ofNullable((User)redisTemplate.opsForValue().get(token)).
                orElseThrow(()->new BaseException(Meta.AuthFail)).getId(),OrderStatus.NotPay.toString()),Meta.UpdateFail)>=PubliceVariable.MinEffectRow){
            //如果redis中存在 该订单的下单库存信息 则恢复原有库存 并删除原有数据
            System.out.println("下单数据"+redisTemplate.opsForValue().get(PubliceVariable.RedisOrderStock+orderId));
            System.out.println("下单redistribution、数据："+PubliceVariable.RedisOrderStock+orderId);
            Optional.ofNullable(redisTemplate.opsForValue().get(PubliceVariable.RedisOrderStock+orderId)).ifPresent(orderStock->{

                goodsService.restoreGoodsStock((ReduceStockDto)orderStock);
                redisTemplate.delete(PubliceVariable.RedisOrderStock+orderId);
            });
        }
        return PubliceVariable.SuccessfulInt;

    }

    //确认订单
    @Override
    public int confirmOrder(String token, String orderId) throws BaseException {

        return CommonUtil.judgeRUD(mOrderMapper.confirmOrder(orderId,OrderStatus.Complete.toString(),CommonUtil.getTimeNormal(),Optional.ofNullable((User)redisTemplate.opsForValue().get(token)).
                orElseThrow(()->new BaseException(Meta.AuthFail)).getId(),OrderStatus.ReceiveGoods.toString()),Meta.UpdateFail);
    }


    private PaySign OrderSaveUtil(OrderDto orderDto) throws BaseException, IOException, NoSuchAlgorithmException {
         User  user = Optional.ofNullable((User)redisTemplate.opsForValue().get(orderDto.getToken())).
                orElseThrow(()->new BaseException(Meta.AuthFail));
        Long user_id = user.getId();

        //设置订单的基本信息
        Order order = new Order();
        String order_id = createOrderId(user_id);
        order.setOrder_id(order_id);
        order.setOrder_status(OrderStatus.NotPay);
        order.setAddress(orderDto.getAddress());
        order.setCity(orderDto.getCity());
        order.setDistrict(orderDto.getDistrict());
        order.setPay_status(OrderPayStatus.NoPayment);
        order.setPhone(orderDto.getPhone());
        order.setPostscript(orderDto.getPostscript());
        order.setProvince(orderDto.getProvince());
        order.setStreet(orderDto.getStreet());
        order.setUser_id(user_id);
        order.setName(orderDto.getName());
        order.setZipcode(orderDto.getZipcode());
        order.setAdd_time(CommonUtil.getTimeNormal());

        //获取基本的订单下商品信息
        List<OrderItem> orderItemLis = new ArrayList<>();
        Long[] freight_id = orderDto.getFreight_id();
        String[] goods_attr_id = orderDto.getGoods_attr_id();
        Long[] goods_id = orderDto.getGoods_id();
        int[] goods_number = orderDto.getGoods_number();
        String[] goods_attr = orderDto.getGoods_attr();
        String[] goods_name = orderDto.getGoods_name();

        //价格获取
        double freight_price = orderDto.getFreight_price();
        double order_price = 0;

        for (int i = 0; i < goods_id.length; i++) {
            OrderItem orderItem = new OrderItem();
            double price = 0;
            //获取商品 信息
            GoodsDetailVo goods = goodsService.getGoodsById(goods_id[i]);
            //如果传入的参数为空
            if (goods_attr_id.length != 0){
                String[] item_goods_attr_id = goods_attr_id[i].split("\\|");
                //加上规格价格
                for (GoodsAttr goodsAttr : goodsAttrService.findAttrArr(item_goods_attr_id)){
                    price+=goodsAttr.getIncrease_price();
                }
                //避免空指针
                orderItem.setGoods_attr(goods_attr[i]);
                orderItem.setGoods_attr_id(goods_attr_id[i]);
            }else {
                //设置参数为空
                orderItem.setGoods_attr("");
            }

            price+=goods.getPrice();
            //设置订单商品详情
            orderItem.setShipping_status(OrderShippingStatus.Unshipped);
            orderItem.setFreight_price(orderDto.getFreight_price());
            orderItem.setFreight_id(freight_id[i]);
            orderItem.setGoods_name(goods_name[i]);
            orderItem.setGoods_id(goods_id[i]);
            orderItem.setGoods_img(orderDto.getGoods_img()[i]);
            orderItem.setGoods_number(goods_number[i]);
            orderItem.setGoods_price(price);
            orderItem.setOrder_id(order_id);
            orderItem.setUser_id(user_id);
            orderItem.setFreight_price(freight_price);
            orderItem.setGoods_total_price(goods_number[i]*price);
            orderItemLis.add(orderItem);

            order_price+=orderItem.getGoods_total_price();
        }
        order.setFreight_price(freight_price);
        order_price+=freight_price;
        order.setOrder_price(order_price);
        //检查存存是否足够 不够抛出异常
        checkStock(orderItemLis);

        CommonUtil.judgeRUD(mOrderMapper.insertOrder(order),Meta.InsertFail);
        //批量插入订单里面的商品
        mOrderMapper.insertOrderItem(orderItemLis);
        //删除购物车的商品 如果没有立即购买则无这部

        if (orderDto.getCart_id()!=null){
            for (String ds:orderDto.getCart_id()){
                System.out.println("购物车："+ds);
            }
            cartService.deleteCart(orderDto.getToken(),orderDto.getCart_id());
        }
        //库存减少
        reduceStock(orderItemLis,order_id);
        // TODO 添加进未完成订单队列 如未付款 30分钟内取消
//        orderTimerService.userOrderCancelteAdd(order_id);
//        return wechatSmallService.unifiedOrder("oe7QQ0SdlZzgEzz6AUv-8H-eRsIw",order_price);
        return wechatSmallService.unifiedOrder(user.getOpenid(),order_price,order_id);
    }


    private String createOrderId(Long user_id){
        return String.valueOf(System.currentTimeMillis())+user_id;
    }

    /**
     * 减少库存
     * @param orderItemLis
     */
    private void reduceStock(List<OrderItem> orderItemLis,String orderId){
        //构造Redis 存储库存减少的对象 并存储 便于之后订单过期后加库存操作
        Long[] goodsIds = new Long[orderItemLis.size()];
        int[] goodsNumbers = new int[orderItemLis.size()];
        for (int i = 0; i < orderItemLis.size(); i++) {
            goodsIds[i] = orderItemLis.get(i).getGoods_id();
            goodsNumbers[i] = orderItemLis.get(i).getGoods_number();
        }
        ReduceStockDto reduceStockDto = new ReduceStockDto(orderId,goodsIds,goodsNumbers);

        redisTemplate.opsForValue().set(PubliceVariable.RedisOrderStock+orderId,
                reduceStockDto, PubliceVariable.RedisOrderStockDueTime,TimeUnit.SECONDS);

        //减少库存
        goodsService.reduceGoodsStock(reduceStockDto);
    }

    /**
     * 检查存存是否足够 不够抛出异常
     * @param orderItemLis
     * @throws BaseException
     */
    private void checkStock(List<OrderItem> orderItemLis) throws BaseException {
        List<Long> idList = new ArrayList<>(orderItemLis.size());
        //查找订单中每个商品信息
        orderItemLis.forEach(orderItem -> idList.add(orderItem.getGoods_id()));
        List<Goods> goodsList = goodsService.getGoodsByIdList(idList);
        System.out.println("goodsList:"+goodsList.size());
        //模拟减少库存
        for (OrderItem orderItem:orderItemLis){
            goodsList.forEach(goods -> {
                System.out.println("goods:"+goods.getGoods_name());
                if (Objects.equals(goods.getId(), orderItem.getGoods_id())){
                    goods.setGoods_number(goods.getGoods_number()-orderItem.getGoods_number());
                }
            });
        }

        //如果有商品库存为负数 则 抛出异常
        for (Goods goods:goodsList){
            if (goods.getGoods_number()<0){
                throw new BaseException(Meta.StockFail);
            }
        }

        //
    }

}
